#ifndef __AHCOMPUTE_WORKER_H__
#define __AHCOMPUTE_WORKER_H__

#include "brick.h"
#include "device.h"
#include "utils.h"

#include <list>
#include <tuple>
#include <memory>

namespace ah_compute
{

template <int TYPE_,
          typename BRICK_
> class Worker
{
public:
    typedef Device<TYPE_, BRICK_> Device;
    typedef BRICK_ Brick;

private:
    Worker(int device_id): m_device_id(0) {}
    Device m_device;

    AHRet Loop(bool& flag)
    {
        bool find_ready = false;
        while(flag) {
            if (m_funcs.size() == 0) {
                // 等待20ms，如果20ms内被唤醒，那就继续执行
                GetWorkerExeCtrl().WaitFor(20);
            }

            std::shared_ptr<Brick> func = nullptr;

            // 判断这次循环是否执行了一次
            find_ready = false;
            // 但是每次都是从队列的最开始处开始查是否具备可执行条件
            auto& it = m_funcs.begin();
            for(; it != m_funcs.end();) {
                if (!it->Ready()) {
                    ++it;
                    continue;
                } else {
                    func = *it;
                    // 每次执行完一个函数之后，就把这个函数从待执行队列中删除掉
                    std::lock_guard<std::mutex> guard(m_funcs_update_mutex);
                    m_funcs.erase(it);
                    find_ready = true;
                    break;
                }
            }

            // 如果所有的任务都还没有准备好，那就让出CPU
            // 重新获得CPU之后，再重头开始检查
            // 因为任务是先进来的，所以先来的任务一定先查询是否具备可执行条件
            if (!find_ready) {
                GetWorkerExeCtrl().WaitFor(20);
                continue;
            }

            // 执行函数
            func->operator();

            // 任务执行完毕，通知其他stream
            GetWorkerExeCtrl().Notify();
        }
    }

    int m_device_id;

    std::list<std::shared_ptr<Brick>> m_funcs = {};
    std::mutex m_funcs_update_mutex;

public:
    ~Worker() {}

    static Worker<Device>& Create(int device_id = 0)
    {
        static Worker<Device> Worker(device_id);
        return Worker;
    }

    AHRet Start()
    {
        std::thread daemon(Loop, std::ref(g_running), this);
        daemon.detach();
    }

};


} // namespace ah_compute

#endif // __AHCOMPUTE_WORKER_H__